#ifndef _SQLITE3EX_H_
#define _SQLITE3EX_H_
#include <iostream>

#define SQLITE3EX_ERROR 1000

#define SQLITE3EX_INTEGER  1
#define SQLITE3EX_FLOAT    2
#define SQLITE3EX_TEXT     3
#define SQLITE3EX_BLOB     4
#define SQLITE3EX_NULL     5

typedef __int64 Int64Ex;
typedef char CharEx;
typedef std::string StringEx;
//typedef wchar_t CharEx;
//typedef std::wstring StringEx;

enum SQLite3TransactionType
{
  SQLITE3EX_TRANSACTION_DEFAULT,
  SQLITE3EX_TRANSACTION_DEFERRED,
  SQLITE3EX_TRANSACTION_IMMEDIATE,
  SQLITE3EX_TRANSACTION_EXCLUSIVE
};

enum SQLite3LimitType
{
  SQLITE3EX_LIMIT_LENGTH              = 0,
  SQLITE3EX_LIMIT_SQL_LENGTH          = 1,
  SQLITE3EX_LIMIT_COLUMN              = 2,
  SQLITE3EX_LIMIT_EXPR_DEPTH          = 3,
  SQLITE3EX_LIMIT_COMPOUND_SELECT     = 4,
  SQLITE3EX_LIMIT_VDBE_OP             = 5,
  SQLITE3EX_LIMIT_FUNCTION_ARG        = 6,
  SQLITE3EX_LIMIT_ATTACHED            = 7,
  SQLITE3EX_LIMIT_LIKE_PATTERN_LENGTH = 8,
  SQLITE3EX_LIMIT_VARIABLE_NUMBER     = 9,
  SQLITE3EX_LIMIT_TRIGGER_DEPTH       = 10
};

enum SQLite3JournalMode
{
  SQLITE3EX_JOURNALMODE_DELETE     = 0,
  SQLITE3EX_JOURNALMODE_PERSIST    = 1,
  SQLITE3EX_JOURNALMODE_OFF        = 2,
  SQLITE3EX_JOURNALMODE_TRUNCATE   = 3,
  SQLITE3EX_JOURNALMODE_MEMORY     = 4,
  SQLITE3EX_JOURNALMODE_WAL        = 5
};

#define SQLITE3EX_OPEN_READONLY         0x00000001
#define SQLITE3EX_OPEN_READWRITE        0x00000002
#define SQLITE3EX_OPEN_CREATE           0x00000004
#define SQLITE3EX_OPEN_NOMUTEX          0x00008000
#define SQLITE3EX_OPEN_FULLMUTEX        0x00010000
#define SQLITE3EX_OPEN_SHAREDCACHE      0x00020000
#define SQLITE3EX_OPEN_PRIVATECACHE     0x00040000

inline void operator++(SQLite3LimitType& value)
{
  value = SQLite3LimitType(value+1);
}

class MemoryBufferData
{
public:
    enum { DefBufSize = 1024 };
    friend class MemoryBuffer;

private:
    MemoryBufferData(size_t size = MemoryBufferData::DefBufSize)
        : m_data(size ? malloc(size) : NULL), m_size(size), m_len(0), m_ref(0)
    {
    }
    ~MemoryBufferData() { free(m_data); }
    void ResizeIfNeeded(size_t newSize)
    {
        if (newSize > m_size)
        {
            void *dataOld = m_data;
            m_data = realloc(m_data, newSize + MemoryBufferData::DefBufSize);
            if ( !m_data )
            {
                free(dataOld);
            }

            m_size = newSize + MemoryBufferData::DefBufSize;
        }
    }
    void IncRef() { m_ref += 1; }
    void DecRef()
    {
        m_ref -= 1;
        if (m_ref == 0)
            delete this;
    }

    void  *m_data;
    size_t m_size;
    size_t m_len;
    size_t m_ref;
};

class MemoryBuffer
{
public:
    MemoryBuffer(size_t size = MemoryBufferData::DefBufSize)
    {
        m_bufdata = new MemoryBufferData(size);
        m_bufdata->IncRef();
    }
    ~MemoryBuffer() { m_bufdata->DecRef(); }
    MemoryBuffer(const MemoryBuffer& src)
        : m_bufdata(src.m_bufdata)
    {
        m_bufdata->IncRef();
    }
    MemoryBuffer& operator=(const MemoryBuffer& src)
    {
        m_bufdata->DecRef();
        m_bufdata = src.m_bufdata;
        m_bufdata->IncRef();
        return *this;
    }
    void  *GetData() const    { return m_bufdata->m_data; }
    size_t GetBufSize() const { return m_bufdata->m_size; }
    size_t GetDataLen() const { return m_bufdata->m_len; }
    void   SetBufSize(size_t size) { m_bufdata->ResizeIfNeeded(size); }
    void   SetDataLen(size_t len)
    {
        m_bufdata->m_len = len;
    }
    void *GetWriteBuf(size_t sizeNeeded)
    {
        m_bufdata->ResizeIfNeeded(sizeNeeded);
        return m_bufdata->m_data;
    }
    void  UngetWriteBuf(size_t sizeUsed) { SetDataLen(sizeUsed); }
    void *GetAppendBuf(size_t sizeNeeded)
    {
        m_bufdata->ResizeIfNeeded(m_bufdata->m_len + sizeNeeded);
        return (char*)m_bufdata->m_data + m_bufdata->m_len;
    }
    void  UngetAppendBuf(size_t sizeUsed)
    {
        SetDataLen(m_bufdata->m_len + sizeUsed);
    }
    void  AppendByte(char data)
    {
        m_bufdata->ResizeIfNeeded(m_bufdata->m_len + 1);
        *(((char*)m_bufdata->m_data) + m_bufdata->m_len) = data;
        m_bufdata->m_len += 1;
    }
    void  AppendData(const void *data, size_t len)
    {
        memcpy(GetAppendBuf(len), data, len);
        UngetAppendBuf(len);
    }
    operator const char *() const { return (const char*)GetData(); }

private:
    MemoryBufferData*  m_bufdata;
};

class SQLite3Exception
{
public:
  SQLite3Exception(int errorCode, const StringEx& errMsg);
  SQLite3Exception(const SQLite3Exception&  e);
  virtual ~SQLite3Exception();
  int GetErrorCode() const { return (m_errorCode & 0xff); }
  int GetExtendedErrorCode() const { return m_errorCode; }
  const StringEx GetMessage() const { return m_errorMessage; }
  static const StringEx ErrorCodeAsString(int errorCode);

private:
  int m_errorCode;
  StringEx m_errorMessage;
};

class SQLite3StatementBuffer
{
public:
  SQLite3StatementBuffer();
  ~SQLite3StatementBuffer();
  const char* Format(const char* format, ...);
  const char* FormatV(const char* format, va_list va);
  operator const char*() const { return m_buffer; }
  void Clear();

private:
  char* m_buffer;
};

class SQLite3FunctionContext
{
public:
  int GetArgCount();
  int GetArgType(int argIndex);
  bool IsNull(int argIndex);
  int GetInt(int argIndex, int nullValue = 0);
  Int64Ex GetInt64(int argIndex, Int64Ex nullValue = 0);
  double GetDouble(int argIndex, double nullValue = 0);
  StringEx GetString(int argIndex, const StringEx& nullValue = "");
  const unsigned char* GetBlob(int argIndex, int& len);
  MemoryBuffer& GetBlob(int argIndex, MemoryBuffer& buffer);
  void SetResult(int value);
  void SetResult(Int64Ex value);
  void SetResult(double value);
  void SetResult(const StringEx& value);
  void SetResult(unsigned char* value, int len);
  void SetResult(const MemoryBuffer& buffer);
  void SetResultNull();
  void SetResultZeroBlob(int blobSize);
  void SetResultArg(int argIndex);
  void SetResultError(const StringEx& errmsg);
  int GetAggregateCount();
  void* GetAggregateStruct(int len);
  static void ExecScalarFunction(void* ctx, int argc, void** argv);
  static void ExecAggregateStep(void* ctx, int argc, void** argv);
  static void ExecAggregateFinalize(void* ctx);
  static int  ExecAuthorizer(void*, int type,
                             const char* arg1, const char* arg2,
                             const char* arg3, const char* arg4);
  static int ExecCommitHook(void* hook);
  static void ExecRollbackHook(void* hook);
  static void ExecUpdateHook(void* hook, int type,
                             const char* database, const char* table,
                             Int64Ex rowid);
  static int ExecWriteAheadLogHook(void* hook, void* dbHandle,
                                   const char* database, int numPages);

private:
  SQLite3FunctionContext(void* ctx, bool isAggregate, int argc = 0, void** argv = NULL);
  SQLite3FunctionContext(SQLite3FunctionContext& ctx);

  void*  m_ctx;
  bool   m_isAggregate;
  int    m_count;
  int    m_argc;
  void** m_argv;
};

class SQLite3ScalarFunction
{
public:
  SQLite3ScalarFunction() {}
  virtual ~SQLite3ScalarFunction() {}
  virtual void Execute(SQLite3FunctionContext& ctx) = 0;
};

class SQLite3AggregateFunction
{
public:
  SQLite3AggregateFunction() { m_count = 0; }
  virtual ~SQLite3AggregateFunction() {}
  virtual void Aggregate(SQLite3FunctionContext& ctx) = 0;
  virtual void Finalize(SQLite3FunctionContext& ctx) = 0;

private:
  int    m_count;
  friend class SQLite3FunctionContext;
};

class SQLite3Authorizer
{
public:
  enum AuthorizationCode
  {
    SQLITE_COPY                =  0,
    SQLITE_CREATE_INDEX        =  1,
    SQLITE_CREATE_TABLE        =  2,
    SQLITE_CREATE_TEMP_INDEX   =  3,
    SQLITE_CREATE_TEMP_TABLE   =  4,
    SQLITE_CREATE_TEMP_TRIGGER =  5,
    SQLITE_CREATE_TEMP_VIEW    =  6,
    SQLITE_CREATE_TRIGGER      =  7,
    SQLITE_CREATE_VIEW         =  8,
    SQLITE_DELETE              =  9,
    SQLITE_DROP_INDEX          = 10,
    SQLITE_DROP_TABLE          = 11,
    SQLITE_DROP_TEMP_INDEX     = 12,
    SQLITE_DROP_TEMP_TABLE     = 13,
    SQLITE_DROP_TEMP_TRIGGER   = 14,
    SQLITE_DROP_TEMP_VIEW      = 15,
    SQLITE_DROP_TRIGGER        = 16,
    SQLITE_DROP_VIEW           = 17,
    SQLITE_INSERT              = 18,
    SQLITE_PRAGMA              = 19,
    SQLITE_READ                = 20,
    SQLITE_SELECT              = 21,
    SQLITE_TRANSACTION         = 22,
    SQLITE_UPDATE              = 23,
    SQLITE_ATTACH              = 24,
    SQLITE_DETACH              = 25,
    SQLITE_ALTER_TABLE         = 26,
    SQLITE_REINDEX             = 27,
    SQLITE_ANALYZE             = 28,
    SQLITE_CREATE_VTABLE       = 29,
    SQLITE_DROP_VTABLE         = 30,
    SQLITE_FUNCTION            = 31,
    SQLITE_SAVEPOINT           = 32,
    SQLITE_MAX_CODE            = SQLITE_SAVEPOINT
  };

  enum AuthorizationResult
  {
    SQLITE_OK     = 0,
    SQLITE_DENY   = 1,
    SQLITE_IGNORE = 2
  };

  virtual ~SQLite3Authorizer() {}
  virtual AuthorizationResult Authorize(AuthorizationCode type,
                                        const StringEx& arg1, const StringEx& arg2,
                                        const StringEx& arg3, const StringEx& arg4) = 0;
  static StringEx AuthorizationCodeToString(SQLite3Authorizer::AuthorizationCode type);
};

class SQLite3Database;

class SQLite3Hook
{
public:
  enum UpdateType
  {
    SQLITE_DELETE              =  9,
    SQLITE_INSERT              = 18,
    SQLITE_UPDATE              = 23
  };
  SQLite3Hook() : m_db(NULL) {}
  virtual ~SQLite3Hook() {}

  virtual bool CommitCallback() { return false; }
  virtual void RollbackCallback() {}
  virtual void UpdateCallback(UpdateType type,
                              const StringEx& database, const StringEx& table,
                              Int64Ex rowid) {}
  virtual int WriteAheadLogCallback(const StringEx& database,
                                    int numPages) { return 0; }
  void SetDatabase(SQLite3Database* db) { m_db = db; }
  SQLite3Database* GetDatabase() const { return m_db; }

private:
  SQLite3Database* m_db;
};

class SQLite3Collation
{
public:
  virtual ~SQLite3Collation() {}
  virtual int Compare(const StringEx& text1, const StringEx& text2) { return text1.compare(text2); }
};

class SQLite3ResultSet
{
public:
  SQLite3ResultSet();
  SQLite3ResultSet(const SQLite3ResultSet& resultSet);
  SQLite3ResultSet(void* db, void* stmt,
                     bool eof, bool first = true, bool ownStmt = true);
  SQLite3ResultSet& operator=(const SQLite3ResultSet& resultSet);
  virtual ~SQLite3ResultSet();
  int GetColumnCount();
  int FindColumnIndex(const StringEx& columnName);
  StringEx GetColumnName(int columnIndex);
  StringEx GetDeclaredColumnType(int columnIndex);
  int GetColumnType(int columnIndex);
  StringEx GetDatabaseName(int columnIndex);
  StringEx GetTableName(int columnIndex);
  StringEx GetOriginName(int columnIndex);
  StringEx GetAsString(int columnIndex);
  StringEx GetAsString(const StringEx& columnName);
  int GetInt(int columnIndex, int nullValue = 0);
  int GetInt(const StringEx& columnName, int nullValue = 0);
  Int64Ex GetInt64(int columnIndex, Int64Ex nullValue = 0);
  Int64Ex GetInt64(const StringEx& columnName, Int64Ex nullValue = 0);
  double GetDouble(int columnIndex, double nullValue = 0.0);
  double GetDouble(const StringEx& columnName, double nullValue = 0.0);
  StringEx GetString(int columnIndex, const StringEx& nullValue = "");
  StringEx GetString(const StringEx& columnName, const StringEx& nullValue = "");
  const unsigned char* GetBlob(int columnIndex, int& len);
  const unsigned char* GetBlob(const StringEx& columnName, int& len);
  MemoryBuffer& GetBlob(int columnIndex, MemoryBuffer& buffer);
  MemoryBuffer& GetBlob(const StringEx& columnName, MemoryBuffer& buffer);
  bool GetBool(int columnIndex);
  bool GetBool(const StringEx& columnName);
  bool IsNull(int columnIndex);
  bool IsNull(const StringEx& columnName);
  bool Eof();
  bool NextRow();
  void Finalize();
  StringEx GetSQL();
  bool IsOk();

private:
  void CheckStmt();

  void* m_db;
  void* m_stmt;
  bool  m_eof;
  bool  m_first;
  int   m_cols;
  bool  m_ownStmt;
};



class SQLite3Table
{
public:
  SQLite3Table();
  SQLite3Table(const SQLite3Table& table);
  SQLite3Table(char** results, int rows, int cols);
  virtual ~SQLite3Table();
  SQLite3Table& operator=(const SQLite3Table& table);
  int GetColumnCount();
  int GetRowCount();
  int FindColumnIndex(const StringEx& columnName);
  StringEx GetColumnName(int columnIndex);
  StringEx GetAsString(int columnIndex);
  StringEx GetAsString(const StringEx& columnName);
  int GetInt(int columnIndex, int nullValue = 0);
  int GetInt(const StringEx& columnName, int nullValue = 0);
  Int64Ex GetInt64(int columnIndex, Int64Ex nullValue = 0);
  Int64Ex GetInt64(const StringEx& columnName, Int64Ex nullValue = 0);
  double GetDouble(int columnIndex, double nullValue = 0.0);
  double GetDouble(const StringEx& columnName, double nullValue = 0.0);
  StringEx GetString(int columnIndex, const StringEx& nullValue = "");
  StringEx GetString(const StringEx& columnName, const StringEx& nullValue = "");
  bool GetBool(int columnIndex);
  bool GetBool(const StringEx& columnName);
  bool IsNull(int columnIndex);
  bool IsNull(const StringEx& columnName);
  void SetRow(int row);
  void Finalize();
  bool IsOk();

private:
    void CheckResults();

    int m_cols;
    int m_rows;
    int m_currentRow;
    char** m_results;
};

class SQLite3Statement
{
public:
  SQLite3Statement();
  SQLite3Statement(const SQLite3Statement& statement);
  SQLite3Statement& operator=(const SQLite3Statement& statement);
  SQLite3Statement(void* db, void* stmt);
  virtual ~SQLite3Statement();

  int ExecuteUpdate();
  SQLite3ResultSet ExecuteQuery(bool transferStatementOwnership = false);
  int GetParamCount();
  int GetParamIndex(const StringEx& paramName);
  StringEx GetParamName(int paramIndex);
  void Bind(int paramIndex, const StringEx& StringExValue);
  void Bind(int paramIndex, int intValue);
  void Bind(int paramIndex, Int64Ex int64Value);
  void Bind(int paramIndex, double doubleValue);
  void Bind(int paramIndex, const char* charValue);
  void Bind(int paramIndex, const unsigned char* blobValue, int blobLen);
  void Bind(int paramIndex, const MemoryBuffer& blobValue);
  void BindBool(int paramIndex, bool value);
  void BindNull(int paramIndex);
  void BindZeroBlob(int paramIndex, int blobSize);
  void ClearBindings();
  StringEx GetSQL();
  void Reset();
  void Finalize();
  bool IsOk();

private:
  void CheckDatabase();
  void CheckStmt();

  void* m_db;
  void* m_stmt;
  bool  m_hasOwnership;
};



class SQLite3Blob
{
public:
  SQLite3Blob();
  SQLite3Blob(const SQLite3Blob& blob);
  SQLite3Blob& operator=(const SQLite3Blob& blob);
  SQLite3Blob(void* m_db, void* blobHandle, bool writable);
  virtual ~SQLite3Blob();

  MemoryBuffer& Read(MemoryBuffer& blobValue, int length, int offset);
  void Write(const MemoryBuffer& blobValue, int offset);
  bool IsOk();
  bool IsReadOnly();
  int GetSize();
  void Finalize();

private:
  void CheckBlob();

  void* m_db;
  void* m_blob;
  bool  m_ok;
  bool  m_writable;
};

class SQLite3Database
{
public:
  SQLite3Database();
  virtual ~SQLite3Database();
  void Open(const StringEx& fileName, const StringEx& key = "",
            int flags = SQLITE3EX_OPEN_READWRITE | SQLITE3EX_OPEN_CREATE);
  void Open(const StringEx& fileName, const MemoryBuffer& key,
            int flags = SQLITE3EX_OPEN_READWRITE | SQLITE3EX_OPEN_CREATE);
  bool IsOpen() const;
  void Close();
  void Backup(const StringEx& targetFileName, const StringEx& key = "", const StringEx& sourceDatabaseName = "main");
  void Backup(const StringEx& targetFileName, const MemoryBuffer& key, const StringEx& sourceDatabaseName = "main");
  void Restore(const StringEx& sourceFileName, const StringEx& key = "", const StringEx& targetDatabaseName = "main");
  void Restore(const StringEx& sourceFileName, const MemoryBuffer& key, const StringEx& targetDatabaseName = "main");
  void Begin(SQLite3TransactionType transactionType = SQLITE3EX_TRANSACTION_DEFAULT);
  void Commit();
  void Rollback(const StringEx& savepointName = "");
  bool GetAutoCommit();
  void Savepoint(const StringEx& savepointName);
  void ReleaseSavepoint(const StringEx& savepointName);
  bool TableExists(const StringEx& tableName, const StringEx& databaseName = "");
  bool EnableForeignKeySupport(bool enable);
  bool IsForeignKeySupportEnabled();
  SQLite3JournalMode SetJournalMode(SQLite3JournalMode mode, const StringEx& database = "");
  SQLite3JournalMode GetJournalMode(const StringEx& database = "");
  bool CheckSyntax(const StringEx& sql);
  bool CheckSyntax(const SQLite3StatementBuffer& sql);
  bool CheckSyntax(const char* sql);
  int ExecuteUpdate(const StringEx& sql);
  int ExecuteUpdate(const SQLite3StatementBuffer& sql);
  int ExecuteUpdate(const char* sql);
  SQLite3ResultSet ExecuteQuery(const StringEx& sql);
  SQLite3ResultSet ExecuteQuery(const SQLite3StatementBuffer& sql);
  SQLite3ResultSet ExecuteQuery(const char* sql);
  int ExecuteScalar(const StringEx& sql);
  int ExecuteScalar(const SQLite3StatementBuffer& sql);
  int ExecuteScalar(const char* sql);
  SQLite3Table GetTable(const StringEx& sql);
  SQLite3Table GetTable(const SQLite3StatementBuffer& sql);
  SQLite3Table GetTable(const char* sql);
  SQLite3Statement PrepareStatement(const StringEx& sql);
  SQLite3Statement PrepareStatement(const SQLite3StatementBuffer& sql);
  SQLite3Statement PrepareStatement(const char* sql);
  Int64Ex GetLastRowId();
  SQLite3Blob GetReadOnlyBlob(Int64Ex rowId,
                                const StringEx& columnName,
                                const StringEx& tableName,
                                const StringEx& dbName = "");
  SQLite3Blob GetWritableBlob(Int64Ex rowId,
                                const StringEx& columnName,
                                const StringEx& tableName,
                                const StringEx& dbName = "");
  SQLite3Blob GetBlob(Int64Ex rowId,
                        const StringEx& columnName,
                        const StringEx& tableName,
                        const StringEx& dbName = "",
                        bool writable = true);
  void Interrupt();
  void SetBusyTimeout(int milliSeconds);
  bool CreateFunction(const StringEx& name, int argCount, SQLite3ScalarFunction& function);
  bool CreateFunction(const StringEx& name, int argCount, SQLite3AggregateFunction& function);
  bool SetAuthorizer(SQLite3Authorizer& authorizer);
  void SetCommitHook(SQLite3Hook* commitHook);
  void SetRollbackHook(SQLite3Hook* rollbackHook);
  void SetUpdateHook(SQLite3Hook* updateHook);
  void SetWriteAheadLogHook(SQLite3Hook* walHook);
  void WriteAheadLogCheckpoint(const StringEx& database);
  void AutoWriteAheadLogCheckpoint(int frameCount);
  void SetCollation(const StringEx& name, SQLite3Collation* collation);
  void GetMetaData(const StringEx& dbName, const StringEx& tableName, const StringEx& columnName,
                   StringEx* dataType = NULL, StringEx* collation = NULL,
                   bool* notNull = NULL, bool* primaryKey = NULL, bool* autoIncrement = NULL);
  void LoadExtension(const StringEx& fileName, const StringEx& entryPoint = "sqlite3_extension_init");
  void EnableLoadExtension(bool enable);
  void ReKey(const StringEx& newKey);
  void ReKey(const MemoryBuffer& newKey);
  bool IsEncrypted() const { return m_isEncrypted; }
  int GetLimit(SQLite3LimitType id);
  int SetLimit(SQLite3LimitType id, int newValue);
  static StringEx LimitTypeToString(SQLite3LimitType type);
  static void InitializeSQLite();
  static void ShutdownSQLite();
  static bool Randomness(int n, MemoryBuffer& random);
  static void SetSharedCache(bool enable);
  static bool IsSharedCacheEnabled() { return ms_sharedCacheEnabled; }
  static StringEx GetVersion();
  static StringEx GetSourceId();
  static bool CompileOptionUsed(const StringEx& optionName);
  static StringEx GetCompileOptionName(int optionIndex);
  static StringEx ConvertJournalMode(SQLite3JournalMode mode);
  static SQLite3JournalMode ConvertJournalMode(const StringEx& mode);
  static bool HasEncryptionSupport();
  static bool HasMetaDataSupport();
  static bool HasLoadExtSupport();
  static bool HasNamedCollectionSupport();
  static bool HasIncrementalBlobSupport();
  static bool HasSavepointSupport();
  static bool HasBackupSupport();
  static bool HasWriteAheadLogSupport();

protected:
  void* GetDatabaseHandle() { return m_db; }
  void SetCollationNeededCallback();
  virtual void SetNeededCollation(const StringEx& collationName) {}
  static int ExecComparisonWithCollation(void* collation, int len1, const void* txt1, int len2, const void* txt2);
  static void ExecCollationNeeded(void* db, void* internalDb, int eTextRep, const char* name);

private:
  SQLite3Database(const SQLite3Database& db);
  SQLite3Database& operator=(const SQLite3Database& db);
  void* Prepare(const char* sql);
  void CheckDatabase();

  void* m_db;
  int   m_busyTimeoutMs;
  bool  m_isEncrypted;

  static bool  ms_sharedCacheEnabled;
  static bool  ms_hasEncryptionSupport;
  static bool  ms_hasMetaDataSupport;
  static bool  ms_hasLoadExtSupport;
  static bool  ms_hasNamedCollectionSupport;
  static bool  ms_hasIncrementalBlobSupport;
  static bool  ms_hasSavepointSupport;
  static bool  ms_hasBackupSupport;
  static bool  ms_hasWriteAheadLogSupport;
};

class SQLite3Transaction
{
public:
  explicit SQLite3Transaction(SQLite3Database* db, SQLite3TransactionType transactionType = SQLITE3EX_TRANSACTION_DEFAULT);
  ~SQLite3Transaction();

  void Commit();
  void Rollback();
  inline bool IsActive()
  {
    return m_database != NULL;
  }

private:
  static void *operator new(size_t size);
  static void operator delete(void *ptr);
  SQLite3Transaction(const SQLite3Transaction&);
  SQLite3Transaction& operator=(const SQLite3Transaction&);
  SQLite3Database* m_database;
};

#endif
